在成功串接咖啡廳資料以及在 Android 專案內顯示 Google 地圖後,接著要來逐步實現我們找咖啡專案的需求 :
上述的需求是有順序的,來依序實現吧~~~
今日實作課程 :
以下範例建立了一個經緯度在雪梨的標記 :
val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
)
接著要在澳洲建立多個標記,標記的 icon 可以用多種方式實作。筆者只會實作專案可能會用到部分,我們先打開 MainActivity 。
把地圖先宣告為全域變數 :
private lateinit var map: GoogleMap
建立標記的 map :
/** map to store place names and locations */
private val places = mapOf(
    "BRISBANE" to LatLng(-27.47093, 153.0235),
    "MELBOURNE" to LatLng(-37.81319, 144.96298),
    "DARWIN" to LatLng(-12.4634, 130.8456),
    "SYDNEY" to LatLng(-33.87365, 151.20689),
    "ADELAIDE" to LatLng(-34.92873, 138.59995),
    "PERTH" to LatLng(-31.952854, 115.857342),
    "ALICE_SPRINGS" to LatLng(-24.6980, 133.8807)
)
建立 PlaceDetails class,用來儲存標記資訊 :
/**
 * This stores the details of a place that used to draw a marker
 */
class PlaceDetails(
    val position: LatLng,
    val title: String = "Marker",
    val snippet: String? = null,
    val icon: BitmapDescriptor = BitmapDescriptorFactory.defaultMarker(),
    val infoWindowAnchorX: Float = 0.5F,
    val infoWindowAnchorY: Float = 0F,
    val draggable: Boolean = false,
    val zIndex: Float = 0F)
建立自定義方法 addMarkersToMap(),用來將標記加到剛剛宣告的 Map 內 :
/**
 * Show all the specified markers on the map
 */
private fun addMarkersToMap() {
    val placeDetailsMap = mutableMapOf(
        // Uses a coloured icon
        "BRISBANE" to MainActivity.PlaceDetails(
            position = places.getValue("BRISBANE"),
            title = "Brisbane",
            snippet = "Population: 2,074,200",
            icon = BitmapDescriptorFactory
                .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)
        ),
        // Uses a custom icon with the info window popping out of the center of the icon.
        "SYDNEY" to MainActivity.PlaceDetails(
            position = places.getValue("SYDNEY"),
            title = "Sydney",
            snippet = "Population: 4,627,300",
            icon = BitmapDescriptorFactory.fromResource(R.drawable.arrow),
            infoWindowAnchorX = 0.5f,
            infoWindowAnchorY = 0.5f
        ),
        // Will create a draggable marker. Long press to drag.
        "MELBOURNE" to MainActivity.PlaceDetails(
            position = places.getValue("MELBOURNE"),
            title = "Melbourne",
            snippet = "Population: 4,137,400",
            draggable = true
        ),
        // Use a vector drawable resource as a marker icon.
        "ALICE_SPRINGS" to MainActivity.PlaceDetails(
            position = places.getValue("ALICE_SPRINGS"),
            title = "Alice Springs",
            icon = vectorToBitmap(
                R.drawable.ic_android, Color.parseColor("#A4C639")
            )
        ),
        // More markers for good measure
        "PERTH" to MainActivity.PlaceDetails(
            position = places.getValue("PERTH"),
            title = "Perth",
            snippet = "Population: 1,738,800"
        ),
        "ADELAIDE" to MainActivity.PlaceDetails(
            position = places.getValue("ADELAIDE"),
            title = "Adelaide",
            snippet = "Population: 1,213,000"
        )
    )
    // add 4 markers on top of each other in Darwin with varying z-indexes
    (0 until 4).map {
        placeDetailsMap.put(
            "DARWIN ${it + 1}", MainActivity.PlaceDetails(
                position = places.getValue("DARWIN"),
                title = "Darwin Marker ${it + 1}",
                snippet = "z-index initially ${it + 1}",
                zIndex = it.toFloat()
            )
        )
    }
    // place markers for each of the defined locations
    placeDetailsMap.keys.map {
        with(placeDetailsMap.getValue(it)) {
            map.addMarker(
                MarkerOptions()
                    .position(position)
                    .title(title)
                    .snippet(snippet)
                    .icon(icon)
                    .infoWindowAnchor(infoWindowAnchorX, infoWindowAnchorY)
                    .draggable(draggable)
                    .zIndex(zIndex))
        }
    }
}
這邊範例還有一個自定義方法 vectorToBitmap() ,是用來將 *Drawable*轉成 BitmapDescriptor,我們之後不一定會用到,大概會暫時用原先 Google 的標記樣式 :
/**
 * Demonstrates converting a [Drawable] to a [BitmapDescriptor],
 * for use as a marker icon.
 */
private fun vectorToBitmap(@DrawableRes id : Int, @ColorInt color : Int): BitmapDescriptor {
    val vectorDrawable: Drawable? = ResourcesCompat.getDrawable(resources, id, null)
    if (vectorDrawable == null) {
        Log.e(TAG, "Resource not found")
        return BitmapDescriptorFactory.defaultMarker()
    }
    val bitmap = Bitmap.createBitmap(vectorDrawable.intrinsicWidth,
        vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
    DrawableCompat.setTint(vectorDrawable, color)
    vectorDrawable.draw(canvas)
    return BitmapDescriptorFactory.fromBitmap(bitmap)
}
最後是  onMapRead() ,前幾天都在和他玩的~~
// Update the map configuration at runtime.
override fun onMapReady(googleMap: GoogleMap) {
    // return early if the map was not initialised properly
    map = googleMap ?: return
    // create bounds that encompass every location we reference
    val boundsBuilder = LatLngBounds.Builder()
    // include all places we have markers for on the map
    places.keys.map { place -> boundsBuilder.include(places.getValue(place)) }
    val bounds = boundsBuilder.build()
    // Set the map coordinates to Kyoto Japan.
    val kyoto = LatLng(35.00116, 135.7681)
    with(map) {
        // Set the map type
        mapType = com.google.android.gms.maps.GoogleMap.MAP_TYPE_NORMAL
        // Display traffic 、指南針、縮放按鈕
        isTrafficEnabled = true
        uiSettings.isCompassEnabled = true
        uiSettings.isZoomControlsEnabled = true
        // Override the default content description on the view, for accessibility mode.
        // Ideally this string would be localised.
        setContentDescription("Map with lots of markers.")
        moveCamera(com.google.android.gms.maps.CameraUpdateFactory.newLatLngBounds(bounds, 50))
    }
    // Add lots of markers to the googleMap.
    addMarkersToMap()
}
這邊我也學案例寫法用比較 Kotlin,現在筆者的 Kotlin 還是寫得和 Java 一樣,不優雅 :(
差不多了,來運行看看 !
阿! 筆者今天改用 Android 裝置,然後用 Vysor 顯示在螢幕上,比較方便操作和截圖~~~
未點擊標記

點擊標記會顯示出標記詳細資訊 (剛剛的自定義類別 PlaceDetails)

寫範例專案的開發人員還特地放 Android 圖標,太可愛了吧~~~
今天只有精力實作範例,一定是連假前症候群,雙十連假快樂壓各位!